﻿using Microsoft.AspNetCore.Mvc.ModelBinding;
using RunUI.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace RunUI.AspNetCore
{
    public class DefaultModelValidationProvider : IModelValidationProvider
    {
        public async Task<ModelStateDictionary> Valid<T>(T model)
        {
            var type = typeof(T);
            return await Valid(model, type);
        }
        ModelStateDictionary modelState = new ModelStateDictionary();

        public async Task<ModelStateDictionary> Valid(object model, Type type)
        {
            await Task.CompletedTask;
            var properties = type.GetProperties();
            foreach (var property in properties)
            {
                var attrs = property.GetCustomAttributes(true);

                foreach (var attr in attrs)
                {
                    var value = property.GetValue(model);

                    ValidationContext validationContext = new ValidationContext(model, null, null);

                    if (attr is RequiredAttribute requiredAttr && !requiredAttr.IsValid(value))
                    {
                        AddModelError(property, requiredAttr.ErrorMessage, $"字段【{property.GetDisplayName()}】不能为空");
                    }
                    else if (attr is MaxLengthAttribute maxLengthAttr && !maxLengthAttr.IsValid(value))
                    {
                        AddModelError(property, maxLengthAttr.ErrorMessage, $"字段【{property.GetDisplayName()}】长度不能大于{maxLengthAttr.Length}");
                    }
                    else if (attr is StringLengthAttribute stringLengthAttribute && !stringLengthAttribute.IsValid(value))
                    {
                        AddModelError(property, stringLengthAttribute.ErrorMessage, $"字段【{property.GetDisplayName()}】长度应在{stringLengthAttribute.MinimumLength}-{stringLengthAttribute.MaximumLength}之间");
                    }
                    else if (attr is MinLengthAttribute minLengthAttribute && !minLengthAttribute.IsValid(value))
                    {
                        AddModelError(property, minLengthAttribute.ErrorMessage, $"字段【{property.GetDisplayName()}】长度不能小于{minLengthAttribute.Length}");
                    }
                    else if (attr is EmailAddressAttribute emailAddressAttribute && !emailAddressAttribute.IsValid(value))
                    {
                        AddModelError(property, emailAddressAttribute.ErrorMessage, $"字段【{property.GetDisplayName()}】不是Email格式");
                    }
                    else if (attr is EnumDataTypeAttribute enumDataTypeAttribute && !enumDataTypeAttribute.IsValid(value))
                    {
                        AddModelError(property, enumDataTypeAttribute.ErrorMessage, $"字段【{property.GetDisplayName()}】不是特定的枚举值");
                    }
                    else if (attr is PhoneAttribute phoneAttribute && !phoneAttribute.IsValid(value))
                    {
                        AddModelError(property, phoneAttribute.ErrorMessage, $"字段【{property.GetDisplayName()}】不是电话格式");
                    }
                    else if (attr is RegularExpressionAttribute regularExpressionAttribute && !regularExpressionAttribute.IsValid(value))
                    {
                        AddModelError(property, regularExpressionAttribute.ErrorMessage, $"字段【{property.GetDisplayName()}】格式验证不通过");
                    }
                    else if (attr is UrlAttribute urlAttribute && !urlAttribute.IsValid(value))
                    {
                        AddModelError(property, urlAttribute.ErrorMessage, $"字段【{property.GetDisplayName()}】不是URL格式");
                    }
                    else if (attr is CompareAttribute compareAttribute)
                    {
                        var result = compareAttribute.GetValidationResult(model, validationContext);
                        if (result != ValidationResult.Success)
                        {
                            AddModelError(property, compareAttribute.ErrorMessage, $"字段【{property.GetDisplayName()}】不是URL格式");
                        }
                    }
                    else if (attr is IAsyncModelPropertyValidator asyncModelPropertyValidator && !await asyncModelPropertyValidator.ValidateAsync(value, property, out var errorMessage))
                    {
                        AddModelError(property, errorMessage, null);
                    }
                    else if (attr is IModelPropertyValidator modelPropertyValidator && !modelPropertyValidator.Validate(value, property, out var errorMessage1))
                    {
                        AddModelError(property, errorMessage1, null);
                    }
                    else if (attr is ValidationAttribute validation)
                    { // validate
                        var result = validation.GetValidationResult(model, validationContext);
                        if (result != ValidationResult.Success)
                        {
                            AddModelError(property, result.ErrorMessage, $"字段【{property.GetDisplayName()}】验证不通过");
                        }
                    }

                }
            }

            var typeAttrubutes = type.GetCustomAttributes(true);
            {
                foreach (var attr in typeAttrubutes)
                {
                    if (attr is IAsyncModelValidator asyncModelValidator && !await asyncModelValidator.ValidateAsync(model, out var property, out var errorMessage))
                    {
                        AddModelError(property, errorMessage, null);
                    }
                    else if (attr is IModelValidator modelValidator && !modelValidator.Validate(model, out var property1, out var errorMessage1))
                    {
                        AddModelError(property1, errorMessage1, null);
                    }
                }
            }

            return modelState;
        }


        private void AddModelError(PropertyInfo property, string errorMessage, string defaultMessage)
        {
            modelState.AddModelError(property.Name, errorMessage.NullWhiteSpaceForDefault(defaultMessage));
        }

    }
}
